using System.Collections.Generic;
using System.Drawing;
using Firestarter.DB.Schema.BO;
using Firestarter.DB.Schema.Logic;
using Firestarter.DB.Schema.Test.BO.TestUtils;
using Firestarter.DB.Schema.Test.Logic;
using Firestarter.DB_DomainModel.Logic;
using FireStarterModeller.BO;
using Firestarter.DB.Schema.UI;
using FireStarterModeller.Logic;
using FireStarterModeller.Test;
using FireStarterModeller.Test.BO;
using FireStarterModeller.UI;
using Habanero.Base;
using Habanero.BO;
using Habanero.DB;
using Habanero.Faces.Base;
using Habanero.Faces.Win;
using NUnit.Framework;
using Rhino.Mocks;
using DockStyle=System.Windows.Forms.DockStyle;

namespace Firestarter.DB.Schema.Test.UI
{
    [TestFixture]
    public class TestDbSchemaReverseEngineerWizardController 
    {
        private static string _testDatabaseName = new TestUtilsDB_MySql().TestDatabaseName;

        [TestFixtureSetUp]
        public void SetupFixture()
        {
            TestUtilsDBSchema.LoadClassDefs();
            GlobalUIRegistry.ControlFactory = new ControlFactoryWin();
        }

        [SetUp]
        public void SetupTest()
        {
            BORegistry.DataAccessor = new DataAccessorInMemory();
            TestUtilsDBSchema.CreateTestDatabase(_testDatabaseName);
            //SchemaTestPackBuilder.SetupDatabaseSchemaTestPack(new CreateTableSqlBuilder_MySql(""), TestUtils.CreateTestDBConnection(_testDatabaseName), _testDatabaseName);

        }

        private static IControlFactory GetControlFactory()
        {
            return GlobalUIRegistry.ControlFactory;
        }

        public DatabaseConnectionInfo CreateTestDatabaseConnectionInfo()
        {
            DatabaseConfig databaseConfig = new DatabaseConfig("Mysql", "localhost", _testDatabaseName, "root", "root", null);
            return DatabaseConnectionInfo.CreateFromDatabaseConfig(databaseConfig);
        }

        //[Test]
        //public void Test_SetDatabaseConnectionInfo()
        //{
        //    //---------------Set up test pack-------------------
        //    DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController();
        //    DatabaseConnectionInfo databaseConnectionInfo = new DatabaseConnectionInfo();
        //    //---------------Assert Precondition----------------

        //    //---------------Execute Test ----------------------
        //    wizardController.DatabaseConnectionInfo = databaseConnectionInfo;
        //    //---------------Test Result -----------------------
        //    Assert.AreSame(databaseConnectionInfo, wizardController.DatabaseConnectionInfo);
        //    Assert.AreSame(databaseConnectionInfo, wizardController.Step1.DatabaseConnectionInfo);
        //}

        //public static ReverseEngineering CreateTestReverseEngineering()
        //{
        //    ReverseEngineering reverseEngineering = new ReverseEngineering();
        //    reverseEngineering.StoredDatabase = CreateTestDatabaseInfo();
        //    reverseEngineering.DatabaseConnectionInfo = CreateTestDatabaseConnection();
        //    reverseEngineering.ReverseEngineeringSettings = new ReverseEngineeringSettings();
        //    return reverseEngineering;
        //}

        private static DatabaseConnectionInfo CreateTestDatabaseConnection()
        {
            DatabaseConnectionInfo databaseConnectionInfo = new DatabaseConnectionInfo
            {
                Vendor = "MySql",
                Server = "localhost",
                Database = "SchemaInfo_test0",
                UserName = "root",
                Password = "root"
            };
            return databaseConnectionInfo;
        }

        private IDBToDMPropertyUpdater GeneratePropertyUpdater()
        {
            return MockRepository.GenerateStub<IDBToDMPropertyUpdater>();
        }

        //public static DBDatabase CreateTestDatabaseInfo()
        //{
        //    DBTableBuilder dbTableBuilder = new DBTableBuilder(new DBTable("ParentTable"));
        //    dbTableBuilder.AddPrimaryKeyColumn();
        //    dbTableBuilder.AddColumn("ParentName");
        //    DBTableBuilder childDBTableBuilder = new DBTableBuilder(new DBTable("ChildTable"));
        //    childDBTableBuilder.AddPrimaryKeyColumn();
        //    //childDBTableBuilder.AddColumn("ChildName");
        //    childDBTableBuilder.AddForeignKey("ForeignKeyName", dbTableBuilder.Table);
        //    DBDatabase dbDatabase = new DBDatabase();
        //    dbDatabase.Tables.Add(dbTableBuilder.Table);
        //    dbDatabase.Tables.Add(childDBTableBuilder.Table);

        //    dbTableBuilder.Table.TableName = dbTableBuilder.Table.TableName.ToLower();
        //    childDBTableBuilder.Table.TableName = childDBTableBuilder.Table.TableName.ToLower();

        //    return dbDatabase;
        //}

        [Test]
        public void Test_Construct()
        {
            //---------------Set up test pack-------------------
            ReverseEngineering reverseEngineering = new ReverseEngineering();
            IDBChangesImporter dbChangesImporter = MockRepository.GenerateStub<IDBChangesImporter>();
            IFireStarterFormsController fireStarterFormsController = MockRepository.GenerateStub<IFireStarterFormsController>();
            IDBToDMPropertyUpdater propertyUpdater = GeneratePropertyUpdater();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController(fireStarterFormsController, reverseEngineering, dbChangesImporter);
            //---------------Test Result -----------------------
            Assert.AreSame(fireStarterFormsController, wizardController.FireStarterFormsController);
            Assert.AreSame(reverseEngineering, wizardController.ReverseEngineering);
            Assert.AreSame(dbChangesImporter, wizardController.DbChangesImporter);
        }

        [Test]
        public void Test_SetReverseEngineeringSettings()
        {
            //---------------Set up test pack-------------------
            ReverseEngineering reverseEngineering = new ReverseEngineering();
            IFireStarterFormsController fireStarterFormsController = MockRepository.GenerateStub<IFireStarterFormsController>();
            DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController(fireStarterFormsController, reverseEngineering, null);
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            wizardController.ReverseEngineering = reverseEngineering;
            //---------------Test Result -----------------------
            Assert.AreSame(reverseEngineering, wizardController.ReverseEngineering);
            //Assert.AreSame(reverseEngineering, wizardController.Step1.ReverseEngineering);
            Assert.AreSame(reverseEngineering, wizardController.Step2.ReverseEngineering);
            Assert.AreSame(reverseEngineering, wizardController.Step3.ReverseEngineering);
        }

        [Test]
        public void Test_WizardController_Step1()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            ReverseEngineering reverseEngineering = new ReverseEngineering();
            IFireStarterFormsController fireStarterFormsController = MockRepository.GenerateStub<IFireStarterFormsController>();
            DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController(fireStarterFormsController, reverseEngineering, null);
            //---------------Test Result -----------------------
            Assert.AreNotEqual(0, wizardController.StepCount);
            Assert.IsInstanceOf(typeof(ChooseDatabaseConnectionWizardStep), wizardController.GetFirstStep());
            Assert.IsInstanceOf(typeof(ChooseDatabaseConnectionWizardStep), wizardController.GetCurrentStep());
            Assert.IsTrue(wizardController.IsFirstStep());
            Assert.IsNotNull(wizardController.ReverseEngineering);
            ChooseDatabaseConnectionWizardStep step1 = (ChooseDatabaseConnectionWizardStep)wizardController.GetFirstStep();
            Assert.AreSame(wizardController.ReverseEngineering, step1.ReverseEngineering);
        }

        //[Test]
        //public void Test_StartWizard()
        //{
        //    //---------------Set up test pack-------------------
        //    DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController();
        //    wizardController.
            
        //    //-------------Assert Preconditions -------------

        //    //---------------Execute Test ----------------------

        //    //---------------Test Result -----------------------

        //}

        //[Test]
        //public void Test_Acceptance_Step2Setup_WithStep1()
        //{
        //    //---------------Set up test pack-------------------

        //    //-------------Assert Preconditions -------------

        //    //---------------Execute Test ----------------------

        //    //---------------Test Result -----------------------
        //}

        [Test]
        public void Test_Acceptance_RunToStep1()
        {
            //---------------Set up test pack-------------------
            ReverseEngineering reverseEngineering = new ReverseEngineering();
            IFireStarterFormsController fireStarterFormsController = MockRepository.GenerateStub<IFireStarterFormsController>();
            DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController(fireStarterFormsController, reverseEngineering, null);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            IWizardControl wizardControl = RunToStep1(wizardController);
            //---------------Test Result -----------------------
            Assert.IsInstanceOf(typeof(ChooseDatabaseConnectionWizardStep), wizardController.GetCurrentStep());
            ChooseDatabaseConnectionWizardStep step1 = (ChooseDatabaseConnectionWizardStep)wizardController.GetCurrentStep();
            Assert.IsNotNull(step1.ReverseEngineering);
            Assert.AreSame(wizardController.ReverseEngineering, step1.ReverseEngineering);
        }

        [Test]
        public void Test_Acceptance_RunToStep2()
        {
            //---------------Set up test pack-------------------
            ReverseEngineering reverseEngineering = new ReverseEngineering();
            IFireStarterFormsController fireStarterFormsController = MockRepository.GenerateStub<IFireStarterFormsController>();
            DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController(fireStarterFormsController, reverseEngineering, null);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            string message;
            IWizardControl wizardControl = RunToStep2(wizardController, out message);
            //---------------Test Result -----------------------
            Assert.IsNull(message);
            Assert.IsInstanceOf(typeof(ChooseObjectTypesWizardStep), wizardController.GetCurrentStep());
            ChooseObjectTypesWizardStep step2 = (ChooseObjectTypesWizardStep)wizardController.GetCurrentStep();
            Assert.IsNotNull(step2.ReverseEngineering);
            Assert.AreSame(wizardController.ReverseEngineering, step2.ReverseEngineering);
        }

        [Test]
        public void Test_Acceptance_RunToStep3()
        {
            //---------------Set up test pack-------------------
            ReverseEngineering reverseEngineering = new ReverseEngineering
                                                        {
                                                            ReverseEngineeringSettings =
                                                                new ReverseEngineeringSettings()
                                                        };
            IFireStarterFormsController fireStarterFormsController = MockRepository.GenerateStub<IFireStarterFormsController>();
            DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController(fireStarterFormsController, reverseEngineering, null);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            string message;
            IWizardControl wizardControl = RunToStep3(wizardController, out message);
            //---------------Test Result -----------------------
            Assert.IsNull(message);
            Assert.IsInstanceOf(typeof(ApproveSchemaChangesWizardStep), wizardController.GetCurrentStep());
            ApproveSchemaChangesWizardStep step3 = (ApproveSchemaChangesWizardStep)wizardController.GetCurrentStep();
            //Assert.AreSame(wizardControl.StoredDatabase, step4.StoredDatabase);
        }

        //[Test]
        //public void Test_Acceptance_RunToStep5()
        //{
        //    //---------------Set up test pack-------------------
        //    ReverseEngineering reverseEngineering = new ReverseEngineering();
        //    DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController(reverseEngineering);
        //    //---------------Assert Precondition----------------
        //    //---------------Execute Test ----------------------
        //    string message;
        //    IWizardControl wizardControl = RunToStep4(wizardController, out message);
        //    //---------------Test Result -----------------------
        //    Assert.IsNull(message);
        //    Assert.IsInstanceOf(typeof(ApproveModelModificationsWizardStep), wizardController.GetCurrentStep());
        //    ApproveModelModificationsWizardStep step5 = (ApproveModelModificationsWizardStep)wizardController.GetCurrentStep();
        //    //Assert.AreSame(wizardControl.DatabaseConnectionInfo, step2.DatabaseConnectionInfo);
        //}

        [Test]
        public void Test_Acceptance_RunToFinish()
        {
            //---------------Set up test pack-------------------
            ReverseEngineering reverseEngineering = new ReverseEngineering
                            {
                                StoredDatabase = TestUtilsDBDatabase.CreateUnsavedValidDBDatabase(),
                                ReverseEngineeringSettings = new ReverseEngineeringSettings()
                            };
            reverseEngineering.SetSolution(TestUtilsDMSolution.CreateUnsavedValidDMSolution());
            IDBChangesImporter dbChangesImporter = MockRepository.GenerateStub<IDBChangesImporter>();
            IFireStarterFormsController fireStarterFormsController = MockRepository.GenerateStub<IFireStarterFormsController>();
            DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController(fireStarterFormsController, reverseEngineering, dbChangesImporter);
            string message;
            RunToStep3(wizardController, out message);

            List<IBOError> errors = new List<IBOError>();
            dbChangesImporter.Stub(importer => importer.ImportDBChanges(reverseEngineering.StoredDatabase, reverseEngineering.GetSolution()))
                .Return(errors);

            //ITransactionCommitter transactionCommitter = MockRepository.GenerateStub<ITransactionCommitter>();
            //IDataAccessor dataAccessor = MockRepository.GenerateStub<IDataAccessor>();
            //dataAccessor.Stub(t => t.CreateTransactionCommitter()).Return(transactionCommitter);
            //BORegistry.DataAccessor = dataAccessor;

            //---------------Assert Precondition----------------
            Assert.IsTrue(wizardController.IsLastStep());
            dbChangesImporter.AssertWasNotCalled(importer => importer.ImportDBChanges(reverseEngineering.StoredDatabase, reverseEngineering.GetSolution()));
            Assert.IsTrue(reverseEngineering.StoredDatabase.Status.IsDirty);
            Assert.IsTrue(reverseEngineering.GetSolution().Status.IsDirty);
            //---------------Execute Test ----------------------
            wizardController.Finish();
            //---------------Test Result -----------------------
            dbChangesImporter.AssertWasCalled(importer => importer.ImportDBChanges(reverseEngineering.StoredDatabase, reverseEngineering.GetSolution()));
            fireStarterFormsController.AssertWasNotCalled(t => 
                t.CreateShowErrorsForm(Arg<IList<IBOError>>.Is.Anything, Arg<string>.Is.Anything, Arg<string>.Is.Anything, Arg<string>.Is.Anything));
/*            Assert.IsFalse(reverseEngineering.StoredDatabase.Status.IsDirty);
            Assert.IsFalse(reverseEngineering.Solution.Status.IsDirty);*/

            //transactionCommitter.AssertWasCalled(committer => committer.AddBusinessObject(reverseEngineering.StoredDatabase));
            //transactionCommitter.AssertWasCalled(committer => committer.AddBusinessObject(reverseEngineering.Solution));
            //transactionCommitter.AssertWasCalled(committer => committer.CommitTransaction());
        }

        [Test]
        public void Test_Acceptance_RunToFinish_WithErrors_ShouldDisplayErrorsAndNotSaveOrFinish()
        {
            //---------------Set up test pack-------------------
            ReverseEngineering reverseEngineering = new ReverseEngineering
                        {
                            StoredDatabase =
                                TestUtilsDBDatabase.CreateUnsavedValidDBDatabase(),
                            ReverseEngineeringSettings = new ReverseEngineeringSettings()
                        };
            reverseEngineering.SetSolution( TestUtilsDMSolution.CreateUnsavedValidDMSolution());
            IDBChangesImporter dbChangesImporter = MockRepository.GenerateStub<IDBChangesImporter>();
            IFireStarterFormsController fireStarterFormsController = MockRepository.GenerateStub<IFireStarterFormsController>();
            DbSchemaReverseEngineerWizardController wizardController = new DbSchemaReverseEngineerWizardController(fireStarterFormsController, reverseEngineering, dbChangesImporter);
            string message;
            RunToStep3(wizardController, out message);

            List<IBOError> errors = new List<IBOError>{new BOError(TestUtilsShared.GetRandomString(), ErrorLevel.Error)};
            dbChangesImporter.Stub(importer => importer.ImportDBChanges(reverseEngineering.StoredDatabase, reverseEngineering.GetSolution()))
                .Return(errors);

            IFormHabanero form = MockRepository.GenerateStub<IFormHabanero>();
            fireStarterFormsController.Stub(t => t.CreateShowErrorsForm(null, null, null, null)).IgnoreArguments().Return(form);

            //ITransactionCommitter transactionCommitter = MockRepository.GenerateStub<ITransactionCommitter>();
            //IDataAccessor dataAccessor = MockRepository.GenerateStub<IDataAccessor>();
            //dataAccessor.Stub(t => t.CreateTransactionCommitter()).Return(transactionCommitter);
            //BORegistry.DataAccessor = dataAccessor;

            //---------------Assert Precondition----------------
            Assert.IsTrue(wizardController.IsLastStep());
            dbChangesImporter.AssertWasNotCalled(importer => importer.ImportDBChanges(reverseEngineering.StoredDatabase, reverseEngineering.GetSolution()));
            Assert.IsTrue(reverseEngineering.StoredDatabase.Status.IsDirty);
            Assert.IsTrue(reverseEngineering.GetSolution().Status.IsDirty);
            //---------------Execute Test ----------------------
            wizardController.Finish();
            //---------------Test Result -----------------------
            dbChangesImporter.AssertWasCalled(importer => importer.ImportDBChanges(reverseEngineering.StoredDatabase, reverseEngineering.GetSolution()));
            fireStarterFormsController.AssertWasCalled(t =>
                t.CreateShowErrorsForm(Arg<IList<IBOError>>.Is.Same(errors), Arg<string>.Is.Anything, Arg<string>.Is.Anything, Arg<string>.Is.Anything));
            form.AssertWasCalled(formHabanero => formHabanero.ShowDialog());
/*            Assert.IsFalse(reverseEngineering.StoredDatabase.Status.IsDirty);
            Assert.IsFalse(reverseEngineering.Solution.Status.IsDirty);*/

            //transactionCommitter.AssertWasCalled(committer => committer.AddBusinessObject(reverseEngineering.StoredDatabase));
            //transactionCommitter.AssertWasCalled(committer => committer.AddBusinessObject(reverseEngineering.Solution));
            //transactionCommitter.AssertWasCalled(committer => committer.CommitTransaction());
        }

        private static IWizardControl RunToStep1(DbSchemaReverseEngineerWizardController wizardController)
        {
            IWizardControl wizardControl = GlobalUIRegistry.ControlFactory.CreateWizardControl(wizardController);
            wizardControl.Start();
            return wizardControl;
        }

        private IWizardControl RunToStep2(DbSchemaReverseEngineerWizardController wizardController, out string message)
        {
            IWizardControl wizardControl = RunToStep1(wizardController);
            string messagePosted = null;
            wizardControl.MessagePosted += delegate(string s) { messagePosted = s; };
            DatabaseConnectionInfo databaseConnectionInfo = CreateTestDatabaseConnectionInfo();
            wizardController.ReverseEngineering.DatabaseConnectionInfo = databaseConnectionInfo;
            wizardControl.Next();
            message = messagePosted;
            return wizardControl;
        }

        private IWizardControl RunToStep3(DbSchemaReverseEngineerWizardController wizardController, out string message)
        {
            IWizardControl wizardControl = RunToStep2(wizardController, out message);
            string messagePosted = message;
            wizardControl.MessagePosted += delegate(string s) { messagePosted = s; };
            wizardControl.Next();
            message = messagePosted;
            return wizardControl;
        }

        //private IWizardControl RunToStep4(DbSchemaReverseEngineerWizardController wizardController, out string message)
        //{
        //    IWizardControl wizardControl = RunToStep3(wizardController, out message);
        //    string messagePosted = message;
        //    wizardControl.MessagePosted += delegate(string s) { messagePosted = s; };
        //    wizardControl.Next();
        //    message = messagePosted;
        //    return wizardControl;
        //}

        [Test]
        [Ignore("This should only be run directly for testing purposes")]
        public void Test_Visually()
        {
            //---------------Set up test pack-------------------
            GlobalRegistry.UIExceptionNotifier = new FormExceptionNotifier();
            DMSolution dmSolution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            ReverseEngineering reverseEngineering = new ReverseEngineering();
            reverseEngineering.ReverseEngineeringSettings = new ReverseEngineeringSettings();
            reverseEngineering.DatabaseConnectionInfo = CreateTestDatabaseConnection();
            reverseEngineering.StoredDatabase = new DBDatabase();
            dmSolution.ReverseEngineering = reverseEngineering;
            IDBToDMImporterFactory dbToDMImporterFactory = new DBToDMImporterFactory(new DBTypeToDMPropertyTypeMapper(new PropertyTypeStorer(dmSolution)), new RelationshipNameGenerator());
            IDBChangesImporter importer = dbToDMImporterFactory.CreateDBChangesImporter();
            IFireStarterFormsController fireStarterFormsController = new FireStarterFormsController(GetControlFactory());
            //---------------Assert Precondition----------------
            Assert.AreEqual(0, dmSolution.AllClasses.Count);
            //---------------Execute Test ----------------------
            DbSchemaReverseEngineeringWizardControl.ShowDBReverseEngineeringWizard(fireStarterFormsController, dmSolution.ReverseEngineering, importer);
            ControlFactoryWin controlFactory = new ControlFactoryWin();
            DMClassAllDetailsControl dmClassAllDetailsControl = new DMClassAllDetailsControl(controlFactory, new FireStarterFormsController(controlFactory));
            dmClassAllDetailsControl.Solution = dmSolution;
            FormWin formWin = new FormWin();
            formWin.Size = new Size(800, 600);
            dmClassAllDetailsControl.Dock = DockStyle.Fill;
            formWin.Controls.Add(dmClassAllDetailsControl);
            formWin.ShowDialog();
            //---------------Test Result -----------------------
            Assert.AreNotEqual(0, dmSolution.AllClasses.Count);
        }
    }

    
}
